//
//  AutoreleasePoolRuntimeTest.m
//  test_simple_project
//
//  自动释放池和运行时特性测试实现
//

#import "AutoreleasePoolRuntimeTest.h"
#import <objc/message.h>

// 关联对象键
const void *kAssociatedStringKey = &kAssociatedStringKey;
const void *kAssociatedIntegerKey = &kAssociatedIntegerKey;

@implementation AutoreleasePoolRuntimeTest

#pragma mark - Autorelease Pool Testing

- (void)testBasicAutoreleasePool {
    NSLog(@"=== Basic Autorelease Pool Test ===");
    
    // 基本自动释放池使用
    @autoreleasepool {
        NSLog(@"Inside autorelease pool");
        
        // 创建自动释放的对象
        NSString *autoreleaseString = [NSString stringWithFormat:@"Autorelease string %@", @"test"];
        NSArray *autoreleaseArray = [NSArray arrayWithObjects:@"item1", @"item2", @"item3", nil];
        NSDictionary *autoreleaseDict = [NSDictionary dictionaryWithObjectsAndKeys:
                                        @"value1", @"key1",
                                        @"value2", @"key2", nil];
        
        NSLog(@"Created objects: %@, %@, %@", autoreleaseString, autoreleaseArray, autoreleaseDict);
    }
    
    NSLog(@"Exited autorelease pool - objects should be released");
}

- (void)testNestedAutoreleasePools {
    NSLog(@"=== Nested Autorelease Pool Test ===");
    
    @autoreleasepool {
        NSLog(@"Outer autorelease pool");
        
        NSString *outerString = [NSString stringWithFormat:@"Outer string"];
        
        @autoreleasepool {
            NSLog(@"Inner autorelease pool");
            
            NSString *innerString = [NSString stringWithFormat:@"Inner string"];
            NSArray *innerArray = @[@"inner1", @"inner2"];
            
            NSLog(@"Inner objects: %@, %@", innerString, innerArray);
        }
        
        NSLog(@"Inner pool drained, outer pool still active");
        NSLog(@"Outer object still accessible: %@", outerString);
    }
    
    NSLog(@"All pools drained");
}

- (void)testAutoreleasePoolWithLoops {
    NSLog(@"=== Autorelease Pool with Loops Test ===");
    
    // 在循环中使用自动释放池，防止内存峰值过高
    NSMutableArray *results = [[NSMutableArray alloc] init];
    
    for (NSInteger i = 0; i < 1000; i++) {
        @autoreleasepool {
            // 每次循环创建临时对象
            NSString *tempString = [NSString stringWithFormat:@"Temp string %ld", (long)i];
            NSData *tempData = [tempString dataUsingEncoding:NSUTF8StringEncoding];
            NSString *base64String = [tempData base64EncodedStringWithOptions:0];
            
            // 保存需要的结果
            if (i % 100 == 0) {
                [results addObject:base64String];
            }
            
            // tempString, tempData, base64String 在这里被释放
        }
    }
    
    NSLog(@"Loop completed, saved %lu results", (unsigned long)results.count);
}

- (void)testAutoreleasePoolPerformance {
    NSLog(@"=== Autorelease Pool Performance Test ===");
    
    NSDate *startTime = [NSDate date];
    
    // 不使用自动释放池的循环
    for (NSInteger i = 0; i < 10000; i++) {
        NSString *string = [[NSString alloc] initWithFormat:@"String %ld", (long)i];
        // 手动释放，模拟ARC之前的行为
        string = nil;
    }
    
    NSTimeInterval withoutPool = [[NSDate date] timeIntervalSinceDate:startTime];
    
    startTime = [NSDate date];
    
    // 使用自动释放池的循环
    for (NSInteger i = 0; i < 10000; i++) {
        @autoreleasepool {
            NSString *string = [NSString stringWithFormat:@"String %ld", (long)i];
            // string将在autoreleasepool结束时释放
        }
    }
    
    NSTimeInterval withPool = [[NSDate date] timeIntervalSinceDate:startTime];
    
    NSLog(@"Without autorelease pool: %.4f seconds", withoutPool);
    NSLog(@"With autorelease pool: %.4f seconds", withPool);
}

- (void)testMemoryManagementInPool {
    NSLog(@"=== Memory Management in Pool Test ===");
    
    __weak NSString *weakReference;
    
    @autoreleasepool {
        NSString *strongString = [NSString stringWithFormat:@"Strong string in pool"];
        weakReference = strongString;
        
        NSLog(@"Inside pool - weak reference valid: %@", weakReference ? @"YES" : @"NO");
        NSLog(@"Strong string: %@", strongString);
    }
    
    // 强制运行自动释放池
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
    
    NSLog(@"After pool - weak reference valid: %@", weakReference ? @"YES" : @"NO");
}

- (void)testLargeObjectCreationInPool {
    NSLog(@"=== Large Object Creation in Pool Test ===");
    
    @autoreleasepool {
        // 创建大量临时对象
        NSMutableArray *largeArray = [[NSMutableArray alloc] init];
        
        for (NSInteger i = 0; i < 10000; i++) {
            NSString *element = [NSString stringWithFormat:@"Element %ld with additional data", (long)i];
            [largeArray addObject:element];
        }
        
        NSLog(@"Created large array with %lu elements", (unsigned long)largeArray.count);
        
        // 对数组进行一些操作
        NSArray *filteredArray = [largeArray filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString *string, NSDictionary *bindings) {
            return [string containsString:@"100"];
        }]];
        
        NSLog(@"Filtered array has %lu elements", (unsigned long)filteredArray.count);
        
        // largeArray 和相关对象将在这里被释放
    }
    
    NSLog(@"Large objects should be released now");
}

#pragma mark - Runtime Features Testing

- (void)testDynamicClassCreation {
    NSLog(@"=== Dynamic Class Creation Test ===");
    
    // 动态创建一个类
    const char *className = "DynamicTestClass";
    Class newClass = objc_allocateClassPair([NSObject class], className, 0);
    
    if (newClass) {
        // 添加实例变量
        class_addIvar(newClass, "dynamicIvar", sizeof(NSString *), log2(sizeof(NSString *)), "@");
        
        // 注册类
        objc_registerClassPair(newClass);
        
        // 创建实例
        id instance = [[newClass alloc] init];
        NSLog(@"Created instance of dynamic class: %@", instance);
        NSLog(@"Instance class: %@", [instance class]);
        
        // 获取类信息
        NSLog(@"Dynamic class name: %s", class_getName(newClass));
        NSLog(@"Dynamic class superclass: %s", class_getName(class_getSuperclass(newClass)));
        
        instance = nil;
        
        // 注意：在实际应用中，动态创建的类通常不会被销毁
        // objc_disposeClassPair(newClass); // 只有在没有实例存在时才能调用
    } else {
        NSLog(@"Failed to create dynamic class");
    }
}

void dynamicMethodImplementation(id self, SEL _cmd, NSString *parameter) {
    NSLog(@"Dynamic method called on %@ with parameter: %@", self, parameter);
}

- (void)testDynamicMethodAddition {
    NSLog(@"=== Dynamic Method Addition Test ===");
    
    Class testClass = [self class];
    
    // 添加实例方法
    SEL dynamicSelector = sel_registerName("dynamicInstanceMethod:");
    IMP dynamicImplementation = (IMP)dynamicMethodImplementation;
    const char *methodTypes = "v@:@"; // void return, self, selector, NSString parameter
    
    BOOL success = class_addMethod(testClass, dynamicSelector, dynamicImplementation, methodTypes);
    NSLog(@"Added dynamic instance method: %@", success ? @"YES" : @"NO");
    
    // 调用动态添加的方法
    if ([self respondsToSelector:dynamicSelector]) {
        ((void(*)(id, SEL, NSString *))objc_msgSend)(self, dynamicSelector, @"test parameter");
    }
}

- (void)testDynamicPropertyAddition {
    NSLog(@"=== Dynamic Property Addition Test ===");
    
    Class testClass = [self class];
    
    // 尝试添加属性（注意：属性主要是元数据，需要手动实现getter/setter）
    objc_property_attribute_t type = {"T", "@\"NSString\""};
    objc_property_attribute_t ownership = {"C", ""}; // copy
    objc_property_attribute_t nonatomic = {"N", ""};
    objc_property_attribute_t ivar = {"V", "_dynamicProperty"};
    
    objc_property_attribute_t attributes[] = {type, ownership, nonatomic, ivar};
    
    BOOL success = class_addProperty(testClass, "dynamicProperty", attributes, 4);
    NSLog(@"Added dynamic property: %@", success ? @"YES" : @"NO");
    
    // 获取属性信息
    objc_property_t property = class_getProperty(testClass, "dynamicProperty");
    if (property) {
        const char *propertyAttributes = property_getAttributes(property);
        NSLog(@"Dynamic property attributes: %s", propertyAttributes);
    }
}

// 原始方法实现
- (void)originalMethodForSwizzling {
    NSLog(@"Original method implementation");
}

// 交换后的方法实现
- (void)swizzledMethodForSwizzling {
    NSLog(@"Swizzled method implementation");
    // 调用原始实现（现在在swizzledMethodForSwizzling中）
    [self swizzledMethodForSwizzling];
}

- (void)testMethodSwizzling {
    NSLog(@"=== Method Swizzling Test ===");
    
    Class testClass = [self class];
    
    // 获取方法
    Method originalMethod = class_getInstanceMethod(testClass, @selector(originalMethodForSwizzling));
    Method swizzledMethod = class_getInstanceMethod(testClass, @selector(swizzledMethodForSwizzling));
    
    // 交换方法实现
    method_exchangeImplementations(originalMethod, swizzledMethod);
    NSLog(@"Methods swizzled");
    
    // 调用"原始"方法（实际会调用交换后的实现）
    [self originalMethodForSwizzling];
    
    // 恢复原始实现
    method_exchangeImplementations(originalMethod, swizzledMethod);
    NSLog(@"Methods restored");
    
    [self originalMethodForSwizzling];
}

- (void)testAssociatedObjects {
    NSLog(@"=== Associated Objects Test ===");
    
    // 创建测试对象
    NSObject *testObject = [[NSObject alloc] init];
    
    // 设置关联对象
    NSString *associatedString = @"Associated String Value";
    NSNumber *associatedNumber = @42;
    
    objc_setAssociatedObject(testObject, kAssociatedStringKey, associatedString, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_setAssociatedObject(testObject, kAssociatedIntegerKey, associatedNumber, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
    // 获取关联对象
    NSString *retrievedString = objc_getAssociatedObject(testObject, kAssociatedStringKey);
    NSNumber *retrievedNumber = objc_getAssociatedObject(testObject, kAssociatedIntegerKey);
    
    NSLog(@"Retrieved string: %@", retrievedString);
    NSLog(@"Retrieved number: %@", retrievedNumber);
    
    // 移除关联对象
    objc_setAssociatedObject(testObject, kAssociatedStringKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
    NSString *afterRemoval = objc_getAssociatedObject(testObject, kAssociatedStringKey);
    NSLog(@"After removal: %@", afterRemoval ?: @"(nil)");
    
    // 移除所有关联对象
    objc_removeAssociatedObjects(testObject);
    
    NSNumber *afterRemovalAll = objc_getAssociatedObject(testObject, kAssociatedIntegerKey);
    NSLog(@"After removing all: %@", afterRemovalAll ?: @"(nil)");
}

- (void)testAssociatedObjectsLifecycle {
    NSLog(@"=== Associated Objects Lifecycle Test ===");
    
    __weak NSString *weakAssociatedObject;
    
    @autoreleasepool {
        NSObject *testObject = [[NSObject alloc] init];
        NSString *strongString = [[NSString alloc] initWithFormat:@"Strong associated string"];
        
        weakAssociatedObject = strongString;
        
        // 使用RETAIN关联
        objc_setAssociatedObject(testObject, "lifecycleTest", strongString, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        
        NSLog(@"Before object deallocation - weak reference valid: %@", weakAssociatedObject ? @"YES" : @"NO");
        
        // testObject超出作用域，关联对象应该被释放
    }
    
    // 强制运行autorelease pool
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
    
    NSLog(@"After object deallocation - weak reference valid: %@", weakAssociatedObject ? @"YES" : @"NO");
}

- (void)testMessageForwarding {
    NSLog(@"=== Message Forwarding Test ===");
    
    MessageForwardingTest *forwardingTest = [[MessageForwardingTest alloc] init];
    
    // 调用不存在的方法，将触发消息转发机制
    if ([forwardingTest respondsToSelector:@selector(dynamicMethod:)]) {
        [forwardingTest dynamicMethod:@"test parameter"];
    } else {
        NSLog(@"Object does not respond to dynamicMethod:");
        
        // 强制发送消息（会触发转发）
        #pragma clang diagnostic push
        #pragma clang diagnostic ignored "-Wundeclared-selector"
        [forwardingTest performSelector:@selector(nonExistentMethod) withObject:nil];
        #pragma clang diagnostic pop
    }
}

BOOL dynamicMethodResolver(id self, SEL _cmd) {
    NSLog(@"Dynamic method resolver called for selector: %s", sel_getName(_cmd));
    return YES;
}

- (void)testDynamicMethodResolution {
    NSLog(@"=== Dynamic Method Resolution Test ===");
    
    Class testClass = [self class];
    
    // 重写resolveInstanceMethod:方法（通常在类实现中完成）
    SEL resolveSelector = @selector(resolveInstanceMethod:);
    IMP resolveImplementation = (IMP)dynamicMethodResolver;
    
    Method resolveMethod = class_getInstanceMethod(testClass, resolveSelector);
    if (resolveMethod) {
        method_setImplementation(resolveMethod, resolveImplementation);
        NSLog(@"Set custom resolve method implementation");
    }
    
    // 现在调用不存在的方法会触发动态解析
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wundeclared-selector"
    SEL undefinedSelector = @selector(undefinedMethod);
    if ([self respondsToSelector:undefinedSelector]) {
        [self performSelector:undefinedSelector];
    }
    #pragma clang diagnostic pop
}

- (void)testKeyValueObserving {
    NSLog(@"=== Key Value Observing Test ===");
    
    KVOTestObject *kvoObject = [[KVOTestObject alloc] init];
    kvoObject.observedProperty = @"Initial Value";
    
    // 添加观察者
    [kvoObject addObserver:self forKeyPath:@"observedProperty" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
    
    // 修改属性值
    NSLog(@"Changing observed property...");
    kvoObject.observedProperty = @"New Value";
    
    // 再次修改
    NSLog(@"Changing observed property again...");
    kvoObject.observedProperty = @"Another New Value";
    
    // 移除观察者
    [kvoObject removeObserver:self forKeyPath:@"observedProperty"];
    
    // 修改属性（不会触发观察）
    NSLog(@"Changing property after removing observer...");
    kvoObject.observedProperty = @"Final Value";
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    NSLog(@"KVO: Property '%@' changed from '%@' to '%@'", 
          keyPath, 
          change[NSKeyValueChangeOldKey], 
          change[NSKeyValueChangeNewKey]);
}

- (void)testKeyValueCoding {
    NSLog(@"=== Key Value Coding Test ===");
    
    KVOTestObject *kvcObject = [[KVOTestObject alloc] init];
    
    // 使用KVC设置值
    [kvcObject setValue:@"KVC Set Value" forKey:@"observedProperty"];
    [kvcObject setValue:@123 forKey:@"numericProperty"];
    
    // 使用KVC获取值
    NSString *stringValue = [kvcObject valueForKey:@"observedProperty"];
    NSNumber *numberValue = [kvcObject valueForKey:@"numericProperty"];
    
    NSLog(@"KVC retrieved string: %@", stringValue);
    NSLog(@"KVC retrieved number: %@", numberValue);
    
    // 集合属性的KVC操作
    NSArray *testArray = @[@"item1", @"item2", @"item3"];
    [kvcObject setValue:testArray forKey:@"arrayProperty"];
    
    // 获取集合属性的计数
    NSNumber *arrayCount = [kvcObject valueForKeyPath:@"arrayProperty.@count"];
    NSLog(@"Array count via KVC: %@", arrayCount);
    
    // 测试不存在的键
    @try {
        [kvcObject setValue:@"test" forKey:@"nonExistentKey"];
    } @catch (NSException *exception) {
        NSLog(@"KVC exception for non-existent key: %@", exception.name);
    }
}

- (void)testRuntimeCategoryRegistration {
    NSLog(@"=== Runtime Category Registration Test ===");
    
    // 创建测试对象
    NSObject *testObject = [[NSObject alloc] init];
    
    // 使用category中定义的动态属性
    testObject.dynamicProperty = @"Dynamic Property Value";
    testObject.dynamicInteger = 42;
    
    NSLog(@"Dynamic property: %@", testObject.dynamicProperty);
    NSLog(@"Dynamic integer: %ld", (long)testObject.dynamicInteger);
    
    // 创建另一个对象测试独立性
    NSObject *anotherObject = [[NSObject alloc] init];
    anotherObject.dynamicProperty = @"Another Value";
    
    NSLog(@"First object dynamic property: %@", testObject.dynamicProperty);
    NSLog(@"Second object dynamic property: %@", anotherObject.dynamicProperty);
}

@end

#pragma mark - Supporting Classes Implementation

@implementation MessageForwardingTest

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSLog(@"Method signature requested for selector: %s", sel_getName(aSelector));
    
    // 为不存在的方法返回一个方法签名
    if (sel_isEqual(aSelector, @selector(dynamicMethod:))) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    }
    
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"Forwarding invocation for selector: %s", sel_getName(anInvocation.selector));
    
    if (sel_isEqual(anInvocation.selector, @selector(dynamicMethod:))) {
        NSString *parameter;
        [anInvocation getArgument:&parameter atIndex:2];
        NSLog(@"Forwarded dynamic method called with parameter: %@", parameter);
    } else {
        [super forwardInvocation:anInvocation];
    }
}

@end

@implementation KVOTestObject

- (instancetype)init {
    self = [super init];
    if (self) {
        _observedProperty = @"Default Value";
        _numericProperty = 0;
        _arrayProperty = @[];
    }
    return self;
}

@end

#pragma mark - Associated Objects Category Implementation

@implementation NSObject (AssociatedObjectTest)

- (NSString *)dynamicProperty {
    return objc_getAssociatedObject(self, kAssociatedStringKey);
}

- (void)setDynamicProperty:(NSString *)dynamicProperty {
    objc_setAssociatedObject(self, kAssociatedStringKey, dynamicProperty, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSInteger)dynamicInteger {
    NSNumber *number = objc_getAssociatedObject(self, kAssociatedIntegerKey);
    return number ? number.integerValue : 0;
}

- (void)setDynamicInteger:(NSInteger)dynamicInteger {
    NSNumber *number = @(dynamicInteger);
    objc_setAssociatedObject(self, kAssociatedIntegerKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end